import { GameObject } from "./gameObject";
import { barrier } from "./barrier";
import { Snake } from "./Snake";

export class GameMap extends GameObject {
    constructor(ctx, parent) {
        super();
        this.ctx = ctx;
        this.parent = parent;
        this.L = 0;

        this.rows = 13;
        this.cols = 14;
        this.inner_barrier_counts = 20;
        this.barriers = [];

        this.snakes = [
            new Snake({ id: 0, color: "#4876EC", r: this.rows - 2, c: 1 }, this),
            new Snake({ id: 0, color: "#F94848", r: 1, c: this.cols - 2 }, this),
        ];
    }
    check_connectivity(hasBarrier, sx, sy, tx, ty) { //这是用来检查联通性的算法。什么flood fill,反正我没做过。但还是很好理解的，毕竟蛇形矩阵我做了好多遍好多遍好多遍啊。
        if (sx == tx && sy == ty) return true;
        hasBarrier[sx][sy] = true;

        let dx = [-1, 0, 1, 0], dy = [0, 1, 0, -1];
        for (let i = 0; i < 4; i++) { //2维也就上下左右四个方向
            let x = sx + dx[i], y = sy + dy[i];
            if (!hasBarrier[x][y] && this.check_connectivity(hasBarrier, x, y, tx, ty)) return true;

        }
        return false;
    }
    barrier_maker() {
        const hasBarrier = [];//布尔数组， 用于判断每个网格是否填充颜色
        for (let r = 0; r < this.rows; r++) { //初始化这个数组
            hasBarrier[r] = [];
            for (let c = 0; c < this.cols; c++) {
                hasBarrier[r][c] = false;
            }
        }
        //给边框填满障碍物。
        for (let r = 0; r < this.rows; r++) {
            hasBarrier[r][0] = hasBarrier[r][this.cols - 1] = true;
        }
        for (let c = 0; c < this.cols; c++) {
            hasBarrier[0][c] = hasBarrier[this.rows - 1][c] = true;
        }
        //随机障碍物, 注意我们要求障碍物是对称的。
        for (let i = 0; i < this.inner_barrier_counts / 2; i++) {
            for (let j = 0; j < 1000; j++) { //我们要判断生成的障碍物不能是重复的
                let r = parseInt(Math.random() * this.rows);
                let c = parseInt(Math.random() * this.cols);
                if (hasBarrier[r][c] || hasBarrier[this.rows - r - 1][this.cols - c - 1]) continue;
                if (r == this.rows - 2 && c == 1 || r == 1 && c == this.cols - 2) { //障碍物不能聚在左下与右上。这里也就是不能与边框相邻
                    continue;
                }
                hasBarrier[r][c] = hasBarrier[this.rows - r - 1][this.cols - c - 1] = true;
                break;
            }
        }
        //如果没有联通，堵住了，那么barrier_maker方法失败,就得重来，1e5 种创建方式，应该有挺多连通性不错的。
        const copy_hasBarrier = JSON.parse(JSON.stringify(hasBarrier));
        if (!this.check_connectivity(copy_hasBarrier, this.rows - 2, 1, 1, this.cols - 2)) {
            return false;
        }

        //创建障碍物
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                if (hasBarrier[r][c]) {
                    this.barriers.push(new barrier(r, c, this));
                }
            }
        }
        return true;
    }
    add_listening_events() {
        this.ctx.canvas.focus();

        const [snake0, snake1] = this.snakes;
        this.ctx.canvas.addEventListener("keydown", e => {
            if (e.key === 'w') snake0.set_direction(0);
            else if (e.key === 'd') snake0.set_direction(1);
            else if (e.key === 's') snake0.set_direction(2);
            else if (e.key === 'a') snake0.set_direction(3);
            else if (e.key === 'ArrowUp') snake1.set_direction(0);
            else if (e.key === 'ArrowRight') snake1.set_direction(1);
            else if (e.key === 'ArrowDown') snake1.set_direction(2);
            else if (e.key === 'ArrowLeft') snake1.set_direction(3);
        });
    }


    start() {
        for (let i = 0; i < 1e5; i++) {
            if (this.barrier_maker()) {
                break;
            }
        }
        this.add_listening_events();

    }
    update_size() {
        //
        this.L = parseInt(Math.min(this.parent.clientWidth / this.cols, this.parent.clientHeight / this.rows));
        this.ctx.canvas.height = this.L * this.rows;
        this.ctx.canvas.width = this.L * this.cols;
    }
    check_ready() {  // 判断两条蛇是否都准备好下一回合了
        for (const snake of this.snakes) {
            if (snake.status !== "idle") return false;
            if (snake.direction === -1) return false;
        }
        return true;
    }



    next_step() {  // 让两条蛇进入下一回合
        for (const snake of this.snakes) {
            snake.next_step();
        }
    }

    check_valid(cell) {  // 检测目标位置是否合法：没有撞到两条蛇的身体和障碍物
        for (const barrier of this.barriers) {
            if (barrier.r === cell.r && barrier.c === cell.c)
                return false;
        }

        for (const snake of this.snakes) {
            let k = snake.cells.length;
            if (!snake.check_tail_increasing()) {  // 当蛇尾会前进的时候，蛇尾不要判断
                k--;
            }
            for (let i = 0; i < k; i++) {
                if (snake.cells[i].r === cell.r && snake.cells[i].c === cell.c)
                    return false;
            }
        }

        return true;
    }

    update() {
        this.update_size();
        if (this.check_ready()) {
            this.next_step();
        }
        this.render();
    }

    render() {
        const color_even = "#AAD751", color_odd = "#A2D149";
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                if ((r + c) % 2 === 1) {
                    this.ctx.fillStyle = color_odd;
                }
                else {
                    this.ctx.fillStyle = color_even;
                }
                this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L);
            }
        }
    }
}